use std::collections::HashMap;

use anyhow::{anyhow, Result};
use reqwest::header::HeaderName;

pub async fn http_get(
    url: &String,
    headers: &HashMap<String, String>,
) -> Result<(HashMap<String, String>, Vec<u8>)> {
    let mut header_map = reqwest::header::HeaderMap::new();
    for (key, value) in headers {
        header_map.insert(
            HeaderName::from_bytes(key.as_bytes())?,
            value.as_str().parse()?,
        );
    }
    let client = if url.starts_with("https:") {
        reqwest::Client::builder().use_rustls_tls().build()?
    } else {
        reqwest::Client::builder().build()?
    };
    let request = client.get(url).headers(header_map);

    tracing::debug!("开始请求:{}", url);
    let response = request
        .send()
        .await
        .map_err(|err| anyhow!("请求错误:{}", err))?;

    let mut headers = HashMap::new();
    for (name, value) in response.headers() {
        headers.insert(name.to_string(), String::from(value.to_str()?));
    }
    let content = response
        .bytes()
        .await
        .map_err(|err| anyhow!("获取内容失败:{}", err))?;

    tracing::debug!("请求结束:{}", content.len());
    Ok((headers, content.to_vec()))
}

pub async fn http_post(
    url: &String,
    headers: &HashMap<String, String>,
    body: Vec<u8>,
) -> Result<(u32, HashMap<String, String>, Vec<u8>)> {
    let mut header_map = reqwest::header::HeaderMap::new();
    for (key, value) in headers {
        header_map.insert(
            HeaderName::from_bytes(key.as_bytes())?,
            value.as_str().parse()?,
        );
    }
    //
    let client = if url.starts_with("https:") {
        reqwest::Client::builder().use_rustls_tls().build()?
    } else {
        reqwest::Client::builder().build()?
    };

    let request = client.post(url).headers(header_map);
    tracing::debug!("开始请求:{}", url);
    let response = request
        .body(body)
        .send()
        .await
        .map_err(|err| anyhow!("请求失败:{}", err))?;

    let mut headers = HashMap::new();
    for (name, value) in response.headers() {
        headers.insert(name.to_string(), String::from(value.to_str()?));
    }

    let content = response
        .bytes()
        .await
        .map_err(|err| anyhow!("获取内容失败:{}", err))?;

    tracing::debug!("请求结束:{}", content.len());
    Ok((200, headers, content.to_vec()))
}

// 下载并保存文件
pub async fn http_download_file(url: &String, to_file: &str) -> Result<()> {
    //
    let mut file = std::fs::File::create(to_file).map_err(|err| anyhow!(err))?;

    tracing::debug!("开始下载文件:{}", url);
    let response = reqwest::get(url)
        .await
        .map_err(|err| anyhow!("下载文件错误:{}", err))?;

    let mut content = std::io::Cursor::new(
        response
            .bytes()
            .await
            .map_err(|err| anyhow!("获取下载内容失败:{}", err))?,
    );
    //
    std::io::copy(&mut content, &mut file).map_err(|err| anyhow!("写文件错误:{}", err))?;
    tracing::debug!("下载完成:{:?}", to_file);

    Ok(())
}

pub async fn http_post_download_file(
    url: &String,
    headers: &HashMap<String, String>,
    body: Vec<u8>,
    to_file: &str,
) -> Result<()> {
    //
    let mut file = std::fs::File::create(to_file).map_err(|err| anyhow!(err))?;

    let mut header_map = reqwest::header::HeaderMap::new();
    for (key, value) in headers {
        header_map.insert(
            HeaderName::from_bytes(key.as_bytes())?,
            value.as_str().parse()?,
        );
    }
    let client = if url.starts_with("https:") {
        reqwest::Client::builder().use_rustls_tls().build()?
    } else {
        reqwest::Client::builder().build()?
    };
    let request = client.post(url).headers(header_map);
    tracing::debug!("开始请求:{}", url);
    let response = request
        .body(body)
        .send()
        .await
        .map_err(|err| anyhow!("请求失败:{}", err))?;

    let mut content = std::io::Cursor::new(
        response
            .bytes()
            .await
            .map_err(|err| anyhow!("获取下载内容失败:{}", err))?,
    );
    //
    std::io::copy(&mut content, &mut file).map_err(|err| anyhow!("写文件错误:{}", err))?;
    tracing::debug!("下载完成:{:?}", to_file);

    Ok(())
}
